<template>
  <div class="container">
    <div class="control">
      <el-tooltip effect="dark" content="聚合距离，在这个距离范围内 features 会聚合在一起。" placement="bottom-end">
        <div class="pading-l-15">聚合距离：</div>
      </el-tooltip>
      <el-slider class="w-280" @input="setDistance" v-model="distance" :min="1" :max="200" />
      <el-tooltip effect="dark" content="聚合对象之间的最小距离，也就是聚合之后的圆圈的距离。不能超过默认的距离。" placement="bottom-end">
        <div class="pading-l-15">最小距离：</div>
      </el-tooltip>
      <el-slider class="w-280" @input="setMinDistance" v-model="minDistance" :min="1" :max="200" />
    </div>
    <div id="map-container"></div>
  </div>
</template>
<script setup lang='ts'>
import { onMounted, ref } from 'vue';
import 'ol/ol.css'
import { Map, View, Feature } from 'ol'
import { Vector as VectorLayer } from 'ol/layer'
import { Cluster, Vector as VectorSource } from 'ol/source.js';
import { Style, Fill as StyleFill, Stroke as StyleStroke, Circle as StyleCircle, Text as StyleText } from 'ol/style'
import { Point as GeomPoint } from 'ol/geom'
import { boundingExtent } from 'ol/extent.js';
import { useTianTileLayer, projection } from '@/hooks'
import { TiandiTileLayerConfigEnum } from '@/enum'

let map: Map, clusterSource: Cluster, clusters: VectorLayer<Cluster>;
const distance = ref(40)
const minDistance = ref(20)

onMounted(() => {
  initMap()
})

// 初始化地图
function initMap() {
  map = new Map({
    target: 'map-container',
    layers: [ ...useTianTileLayer(TiandiTileLayerConfigEnum.SL) ],
    view: new View({
      center: [-29.759955,9.722733],
      projection: projection,
      zoom: 3,
      maxZoom: 17,
      minZoom: 1
    })
  })
  getCoordinate()
}

// 获取坐标
function getCoordinate() {
  // 随机生成模拟
  const coordinates = []
  for (let i = 0; i < 20000; ++i) {
    let coordinate = [generateLongitude(), generateLatitude()]
    coordinates.push(coordinate)
  }
  addClusterPoint(coordinates)
  addEvent()
}

// 聚合图
function addClusterPoint(coordinates: Array<number[]>) {
  const features: Array<Feature<GeomPoint>> = []
  coordinates.forEach(coordinate => {
    const Point = new Feature({
      type: 'point',
      geometry: new GeomPoint(coordinate)
    })
    // //设置点的样式信息
    // Point.setStyle(new Style({
    //   image: new StyleCircle({
    //     radius: 4,
    //     fill: new StyleFill({
    //       color: 'yellow'
    //     })
    //   })
    // }))
    features.push(Point)
  })
  const source = new VectorSource({
    features: features
  })
  clusterSource = new Cluster({
    distance: distance.value,
    minDistance: minDistance.value,
    source: source,
  })
  // 也可以换成Heatmap Layer 展示热力图聚合图
  let styleCache: any = {}
  clusters = new VectorLayer({
    source: clusterSource,
    style: feature => {
      const size = feature.get('features').length;
      let style = styleCache[size];
      if (!style) {
        style = new Style({
          image: new StyleCircle({
            radius: 10,
            stroke: new StyleStroke({
              color: 'blue',
            }),
            fill: new StyleFill({
              color: 'red',
            })
          }),
          text: new StyleText({
            text: size.toString(),
            fill: new StyleFill({
              color: '#fff',
            })
          })
        })
        styleCache[size] = style
      }
      return style;
    }
  })
  map.addLayer(clusters)
}

// 箭头地图点击/移动
function addEvent() {
  map.on('pointermove', e => {
    const pixel = map.getEventPixel(e.originalEvent);
    const hit = map.hasFeatureAtPixel(pixel);
    if(hit) {
      map.getTargetElement().style.cursor = 'pointer'
    }
  })
  map.on('click', (e) => {
    clusters.getFeatures(e.pixel).then((clickedFeatures) => {
      if (clickedFeatures.length) {
        // Get clustered Coordinates
        const features = clickedFeatures[0].get('features');
        if (features.length > 1) {
          const extent = boundingExtent(features.map((r: any) => r.getGeometry().getCoordinates()));
          map.getView().fit(extent, {duration: 1000, padding: [50, 50, 50, 50]});
        }
      }
    })
  })
}

// 设置聚合距离
function setDistance() {
  clusterSource.setDistance(distance.value)
}

// 设置最小距离
function setMinDistance() {
  clusterSource.setMinDistance(minDistance.value)
}

function generateLongitude() {
  // -100 ~ 100
  return Number((Math.random() * 100 - 50).toFixed(3))
}

function generateLatitude() {
  return Number((Math.random() * 60 - 30).toFixed(3))
}
</script>
<style scoped>
.container {
  width: 100%;
  height: 100%;
}
.control {
  width: 100%;
  height: 35px;
  display: flex;
  align-items: center;
}
#map-container {
  width: 100%;
  height: calc(100% - 35px);
  position: relative;
}
.pading-l-15 {
  padding-left: 15px;
}

.w-280 {
  width: 280px;
}

.margin-lt-15 {
  margin-left: 15px;
}


</style>